import {ref} from 'vue'

export function useDownloadFile() {
    //下载进度
    const progress = ref(0)
    //状态
    const status = ref<'idle' | 'downloading' | 'ready' | 'success' | 'error' | 'canceled'>('idle')
    //已下载总字节数
    const downloadedSize = ref(0)
    //文件总字节数
    const totalSize = ref(0)
    //下载文件二进制对象
    const blob = ref<Blob | null>(null)
    //取消下载控制器
    let controller: AbortController | null = null

    /**
     * 开始下载
     * @param url 下载地址
     * @param onProgress 下载进度回调函数
     * @param onSuccess 下周成功回调函数
     */
    const start = async (url: string, onProgress?: (received: number, total: number) => void, onSuccess?: () => void) => {
        try {
            controller = new AbortController()
            status.value = 'downloading'
            progress.value = 0
            downloadedSize.value = 0
            totalSize.value = 0

            // 获取总大小
            const headRes = await fetch(url, {method: 'HEAD'})
            const len = headRes.headers.get('Content-Length')
            if (len) totalSize.value = parseInt(len, 10)

            const res = await fetch(url, {signal: controller.signal})
            if (!res.ok || !res.body) throw new Error('下载失败或无响应体')

            const total = totalSize.value || Number(res.headers.get('Content-Length')) || -1
            let received = 0
            const reader = res.body.getReader()

            const stream = new ReadableStream({
                start(controller) {
                    function pump() {
                        reader.read().then(({done, value}) => {
                            if (done) {
                                controller.close()
                                onProgress?.(received, total)
                                return
                            }
                            if (value) {
                                received += value.length
                                downloadedSize.value = received
                                totalSize.value = total
                                if (total > 0) {
                                    progress.value = Math.floor((received / total) * 100)
                                }
                                onProgress?.(received, total)
                                controller.enqueue(value)
                            }
                            pump()
                        }).catch(err => {
                            if (err.name === 'AbortError') {
                                status.value = 'canceled'
                            } else {
                                throw err
                            }
                        })
                    }

                    pump()
                }
            })

            blob.value = await new Response(stream).blob()
            status.value = 'ready'
            onSuccess?.()
        } catch (err) {
            console.error(err)
            status.value = 'error'
        }
    }

    /**
     * 取消下载
     */
    const cancel = () => controller?.abort()

    /**
     * 保存文件成指定名字
     * @param filename 文件名字
     */
    const save = (filename: string) => {
        if (!blob.value) return
        const url = URL.createObjectURL(blob.value)
        const a = document.createElement('a')
        a.href = url
        a.download = filename
        a.click()
        URL.revokeObjectURL(url)
        status.value = 'success'
    }

    return {
        progress,
        status,
        downloadedSize,
        totalSize,
        blob,
        start,
        cancel,
        save
    }
}
